Skip to main content

Flipping Cookie

You can get a cookie for my website, but it won't help you read the flag... I think.

source.py
from Crypto.Cipher import AES
import os
from Crypto.Util.Padding import pad, unpad
from datetime import datetime, timedelta

KEY = ?
FLAG = ?

@chal.route('/flipping_cookie/check_admin/<cookie>/<iv>/')
def check_admin(cookie, iv):
cookie = bytes.fromhex(cookie)
iv = bytes.fromhex(iv)

try:
cipher = AES.new(KEY, AES.MODE_CBC, iv)
decrypted = cipher.decrypt(cookie)
unpadded = unpad(decrypted, 16)
except ValueError as e:
return {"error": str(e)}

if b"admin=True" in unpadded.split(b";"):
return {"flag": FLAG}
else:
return {"error": "Only admin can read the flag"}


@chal.route('/flipping_cookie/get_cookie/')
def get_cookie():
expires_at = (datetime.today() + timedelta(days=1)).strftime("%s")
cookie = f"admin=False;expiry={expires_at}".encode()

iv = os.urandom(16)
padded = pad(cookie, 16)
cipher = AES.new(KEY, AES.MODE_CBC, iv)
encrypted = cipher.encrypt(padded)
ciphertext = iv.hex() + encrypted.hex()

return {"cookie": ciphertext}

Solution:

This WriteUp Solution is password protected by the flag of the challenge.
Point here to Notice is that the cookie is encrypted with AES CBC mode and the IV is generated randomly. The cookie is also padded with PKCS7 padding. The cookie is decrypted and checked for the string "admin=True". If it is present, the flag is returned.since in CBC mode decrypted message is XOR'd with IV so if we change IV such that the decrypted message is "admin=True" then we can get the flag.
#take two strings with equal length 16 bytes length
xorkey = xorstr(b"admin=False;expr",b"admin=True;expry")
new_iv = xorstr(iv,xorkey)

Complete code for the same is :

import requests
from Crypto.Util.strxor import strxor

url='https://aes.cryptohack.org/flipping_cookie/'

r = requests.get(url+'get_cookie/')
data=r.json()['cookie']
iv=bytes.fromhex(data[:32])

#taking two strings with 16 bytes length
xor_key=strxor(b'admin=False;expi',b'admin=True;expir')
new_iv=strxor(iv,xor_key).hex()

r=requests.get(url+'check_admin/'+data[32:]+'/'+new_iv)
print(r.json()['flag'])

After running following code you will get flag as crypto{4u7h3n71c4710n_15_3553n714l}